<?php

class Cache_Slot 
{
    /**
     * Tags attached to this slot.
     * 
     * @var array of Dklab_Cache_Tag
     */
    private $_tags;
    
    /**
     * Calculated ID associated to this slot.
     * 
     * @var string
     */
    private $_id;
    
    /**
     * Lifetime of this slot.
     * 
     * @var int
     */
    public $_lifetime = 86400;

    /**
     * Фабрика слотов. Определяет тип переданного аргумента и создает нужный слот.
     * 
     * @param mixed $param
     * @return Cache_Slot
     */
    public static function factory($param, $lifetime)
    {
    	if ($param instanceof Db_Select) {
    		return new Cache_Slot_Rowset($param, $lifetime);
    	} elseif (is_string($param)) {
    		return new Cache_Slot_String($param, $lifetime);
    	} elseif (is_numeric($param)) {
    		return new Cache_Slot_Number($param, $lifetime);
    	} elseif (is_array($param)) {
    		return new Cache_Slot_Array($param, $lifetime);
    	}
    	
    	throw new Cache_Exception('Unknown slot type given');
    }
    
    /**
     * Creates a new slot object.
     * 
     * @param string $id   ID of this slot.
     * @return Dklab_Cache_Slot
     */
    public function __construct($id, $lifetime = 86400)
    {
        $this->_id = $id;
        if (!$lifetime) {
        	$lifetime = 86400;
        }
        
        $this->_lifetime = $lifetime;
        $this->_tags = array();
    }
    
	/**
	 * Return backend for caching.
	 * 
	 * @return Zend_Cache_Backend_Interface
	 */
	protected function _getBackend()
	{
		return Cache_Manager::getInstance()->getBackend();
	}
    
    
    /**
     * Loads a data of this slot. If nothing is found, returns false.
     * 
     * @return mixed   Complex data or false if no cache entry is found.
     */
    public function load()
    {
        $raw = $this->_getBackend()->load($this->_id);
        return $raw;
    }
    
    
    /**
     * Saves a data for this slot. 
     * 
     * @param mixed $data   Data to be saved.
     * @return void
     */
    public function save($data)
    {
        $tags = array();
        foreach ($this->_tags as $tag) {
            $tags[] = $tag->getNativeId();
        }

        $this->_getBackend()->save($data, $this->_id, $tags, $this->_lifetime);
    }
    
	/**
	 * Получает данные слота.
	 * В случае промаха кеша выполняет все необходимые данные.
	 * 
	 * @return mixed
	 */
	public function get()
	{
		$result = $this->load();
		
		if ($result === false) {
			$result = $this->_getWithoutCache();
			$this->save($result);
		}
		
		return $result;
	}
	
	/**
	 * Используется в случае промаха кеша, получение данных.
	 * 
	 * @return mixed
	 */
	protected function _getWithoutCache()
	{
		throw new Cache_Exception(sprintf('Автоматическое получение данных для данного слота не предусмотрено (%s)', get_class($this)));
	}
    
    /**
     * Removes a data of specified slot.
     * 
     * @return void
     */
    public function remove()
    {
        $this->_getBackend()->remove($this->_id);
    }
    
    
    /**
     * Associates a tag with current slot.
     * 
     * @param string|Cache_Tag $tag   Tag object to associate.
     * @return void
     */
    public function addTag($tag)
    {
    	if (is_string($tag)) {
    		$tag = new Cache_Tag($tag);
    	}
    	
    	if (!$tag instanceof Cache_Tag) {
    		throw new Cache_Exception("Invalid tag: `$tag`");
    	}

    	$this->_tags[] = $tag;
    }


}
